package model

import (
	"log"
	"strconv"
	"webapp/utils"
)

type HardwareClass struct {
	ClassId   int
	ClassName string
}

type HardwareItem struct {
	ItemId   int
	ItemName string
	ClassId  int
	ItemAttr map[string]string
}

type HardwareItemAttr struct {
	ItemId   int
	AttrName string
	AttrVal  string
}

func (hardwareClass *HardwareClass) AddHardWareClass() error {
	sqlStr := "insert into hardware_classes(class_id,class_name) values (?,?)"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(hardwareClass.ClassId, hardwareClass.ClassName)
	if err != nil {
		return err
	}
	log.Println("add class", hardwareClass)
	err = inStmt.Close()
	return err
}
func (hardwareClass *HardwareClass) DeleteHardWareClass() error {
	sqlStr := "delete from hardware_classes where class_id = ?"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(hardwareClass.ClassId)
	if err != nil {
		return err
	}
	itemList, err := GetHardwareItemListByClassId(hardwareClass.ClassId)
	if err != nil {
		return err
	}
	for _, each := range itemList {
		err := each.DeleteHardwareItem()
		if err != nil {
			return err
		}
	}
	log.Println("remove class", hardwareClass)
	inStmt.Close()
	return err
}
func (hardwareClass *HardwareClass) ModifyHardwareClass() error {
	sqlStr := "update hardware_classes set class_name = ? where class_id = ?"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(hardwareClass.ClassName, hardwareClass.ClassId)
	if err != nil {
		return err
	}

	log.Println("modify class to ", hardwareClass)
	inStmt.Close()
	return err
}
func (item *HardwareItem) AddHardwareItem() error {
	sqlStr := "insert into hardware_items(item_id,item_name,class_id) values (?,?,?)"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(item.ItemId, item.ItemName, item.ClassId)
	if err != nil {
		return err
	}
	err = addItemAttrs(item)
	log.Println("add item", item)
	inStmt.Close()
	return err
}
func (item *HardwareItem) DeleteHardwareItem() error {
	sqlStr := "delete from hardware_items where item_id = ?"
	sqlStr4Attr := "delete from hardware_attrs where item_id = ?"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	inStmt.Exec(item.ItemId)

	inStmt, err = utils.DB.Prepare(sqlStr4Attr)
	if err != nil {
		return err
	}
	inStmt.Exec(item.ItemId)
	log.Println("remove item", item)
	err = inStmt.Close()
	return err
}
func (item *HardwareItem) ModifyHardwareItem() error {
	sqlStr := "update hardware_items set item_name = ? , class_id = ? where item_id = ?"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(item.ItemName, item.ClassId, item.ItemId)
	if err != nil {
		return err
	}

	log.Println("modify item name/class to", item)
	inStmt.Close()
	return err
}

func GetHardwareClassNewId() int {
	sqlStr := "select max(class_id) from hardware_classes"
	rows, err := utils.DB.Query(sqlStr)
	var ret int
	if err != nil {
		return -1
	}
	rows.Next()
	rows.Scan(&ret)
	err = rows.Close()
	return ret + 1
}

func GetHardwareItemNewId() int {
	sqlStr := "select max(item_id) from hardware_items"
	rows, err := utils.DB.Query(sqlStr)
	var ret int
	if err != nil {
		return -1
	}
	rows.Next()
	rows.Scan(&ret)
	err = rows.Close()
	return ret + 1
}

func HWItemId2HWClassId(itemId int) (int, error) {
	sqlStr := `select class_id from hardware_items where item_id=` + strconv.Itoa(itemId)
	rows, err := utils.DB.Query(sqlStr)
	var ret int
	if err != nil {
		return -1, err
	}
	rows.Next()
	rows.Scan(&ret)
	err = rows.Close()
	return ret, err
}

func HWClassId2HWItemId(classId int) (int, error) {
	sqlStr := `select item_id from hardware_items where class_id=` + strconv.Itoa(classId)
	rows, err := utils.DB.Query(sqlStr)
	var ret int
	if err != nil {
		return -1, err
	}
	rows.Next()
	rows.Scan(&ret)
	return ret, err
}

func GetHardwareClassList() ([]*HardwareClass, error) {
	sqlStr := "select * from hardware_classes"
	rows, _ := utils.DB.Query(sqlStr)
	var class_id int
	var class_name string
	var hardwareClassList []*HardwareClass
	for rows.Next() {

		err := rows.Scan(&class_id, &class_name)
		if err != nil {
			return nil, err
		}
		hc := &HardwareClass{class_id, class_name}
		hardwareClassList = append(hardwareClassList, hc)
	}
	err := rows.Close()
	return hardwareClassList, err
}

func addItemAttrs(item *HardwareItem) error {
	sqlStr := "insert into hardware_attrs(item_id,attr_name,attr_val) values (?,?,?)"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	for k, v := range item.ItemAttr {
		_, err := inStmt.Exec(item.ItemId, k, v)
		if err != nil {
			return err
		}
	}
	err = inStmt.Close()
	return err
}

func getItemAttrs(item_id int) (map[string]string, error) {
	sqlStr := "select attr_name,attr_val from hardware_attrs where item_id=" + strconv.Itoa(item_id)
	rows, _ := utils.DB.Query(sqlStr)
	var attrName string
	var attrVal string
	ret := make(map[string]string)
	for rows.Next() {
		err := rows.Scan(&attrName, &attrVal)
		if err != nil {
			return nil, err
		}
		ret[attrName] = attrVal
	}
	err := rows.Close()
	return ret, err
}

func GetHardwareItemList() ([]*HardwareItem, error) {
	sqlStr := "select item_id,item_name,class_id from hardware_items"
	rows, _ := utils.DB.Query(sqlStr)
	var itemId int
	var itemName string
	var classId int

	var hardwareItemList []*HardwareItem
	for rows.Next() {

		err := rows.Scan(&itemId, &itemName, &classId)
		if err != nil {
			return nil, err
		}
		attrs, err := getItemAttrs(itemId)
		if err != nil {
			return nil, err
		}
		item := &HardwareItem{ItemId: itemId, ItemName: itemName, ClassId: classId, ItemAttr: attrs}
		hardwareItemList = append(hardwareItemList, item)
	}
	err := rows.Close()

	return hardwareItemList, err
}

func GetHardwareItemListByClassId(classIdInput int) ([]*HardwareItem, error) {
	sqlStr := "select item_id,item_name,class_id from hardware_items where class_id=" + strconv.Itoa(classIdInput)
	rows, _ := utils.DB.Query(sqlStr)
	var itemId int
	var itemName string
	var classId int

	var hardwareItemList []*HardwareItem
	for rows.Next() {

		err := rows.Scan(&itemId, &itemName, &classId)
		if err != nil {
			return nil, err
		}
		attrs, err := getItemAttrs(itemId)
		if err != nil {
			return nil, err
		}
		item := &HardwareItem{ItemId: itemId, ItemName: itemName, ClassId: classId, ItemAttr: attrs}
		hardwareItemList = append(hardwareItemList, item)
	}

	err := rows.Close()
	return hardwareItemList, err
}

func ModifyHardwareItemAttr(itemId int, attrName string, newAttrVal string) error {
	sqlStr := "update hardware_attrs set attr_val = ? where item_id = ? and attr_name=?"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(newAttrVal, itemId, attrName)
	if err != nil {
		return err
	}
	err = inStmt.Close()
	return err
}

func AddHardwareItemAttr(itemId int, attrName string, attrVal string) error {
	sqlStr := "insert into hardware_attrs(item_id,attr_name,attr_val) values (?,?,?)"
	inStmt, err := utils.DB.Prepare(sqlStr)
	if err != nil {
		return err
	}

	_, err = inStmt.Exec(itemId, attrName, attrVal)
	if err != nil {
		return err
	}

	err = inStmt.Close()
	return err
}

func DeleteHardwareItemAttr(itemId int, attrName string) error {
	sqlStr4Attr := "delete from hardware_attrs where item_id = ? and attr_name=?"
	inStmt, err := utils.DB.Prepare(sqlStr4Attr)
	if err != nil {
		return err
	}
	_, err = inStmt.Exec(itemId, attrName)
	if err != nil {
		return err
	}
	err = inStmt.Close()
	return err
}
